__author__ = 'maikel'

import math
import numpy as np
from utilsP4 import *

# Carreguem les dades de la borsa mitjacant la funcio loadStockData
data={}
companies=['GOOG','MSFT','IBM','YHOO','FB']
#companies=['YHOO']
for c in companies:
    data[c]=loadStockData(c)

class AdWin:
    """
        Finestra lliscant adaptativa que permet trobar la mitja de totes les dades que es
        van inserin i que permet trobar canvis bruscos
        en elles i adaptar-se a ells a partir d'un valor de confianca indicat per l'usuari.
    """
    def __init__(self, d):
        """
            Constructor de la finestra.

            param d Confianca el canvi. Com mes gran mes facil sera detectar un canvi.
        """
        self.data = []
        self.length = 0
        self.rel = d
        self.m = 0.0

    def eCut(self, w1, w2):
        """
            Calcula epsilon, y comprueba si cumple la condicion para eliminar.
        """
        m = 1.0 / ( (1.0/len(w1)) + (1.0/len(w2)) )
        rel_prima = self.rel / float(len(w1) + len(w2))
        epsilon = math.sqrt( (1.0/(2.0*m)) * math.log(4.0/rel_prima) )
        #print len(w1), len(w2), "\teps: ", epsilon, "\tu_w1: ", np.mean(w1), "\tu_w2: ", np.mean(w2)
        return math.fabs(np.mean(w1) - np.mean(w2)) > epsilon

    def add(self, x_t):
        """
            Afegeix una nova dada a la finestra i despres de comprovar si hi ha hagut un canvi actualitza les dades necessaries.

            param x_t Nova dada.

            return self.m Mitja de les dades del interior de la finestra
            return 	0 si no hi ha hagut cap canvi significatiu
                    1 si hi ha hagut un canvi i la mitja ha disminuit
                    -1 si hi ha hagut un canvi i la mitja ha augmentat
        """
        self.data.append(x_t)
        self.length += 1

        idx = 1
        canvi = 0
        while idx < len(self.data):
            w1 = self.data[:idx]
            w2 = self.data[idx:]

            if self.eCut(w1, w2):
                self.data = w2
                self.length -= len(w1)
                canvi = 2 # Indicamos cambio
                idx = 0

            idx += 1

        mean = np.mean(self.data)
        if canvi == 2:
            if (mean < self.m):
                canvi = 1
            elif (mean > self.m):
                canvi = -1

        self.m = mean

        return mean, canvi

def estrategia(broker,data,badget=100000.00):
    """
        Definim una estrategia de joc.
        Parametres d'entrada : StockMarketWin
                             : Dades - dades que utilizarem per fer el test
                             : badget- quantitat de diners que volem jugar
    """
    # Definim els parametres inicials de l'estrategia
    # Gastem el 50% del badget en accions
    n_stocks= math.floor((badget/2)/float(data[0]))
    init_stocks=n_stocks
    # Descomptem del badget el valor de les acciones que hem comprat
    badget = badget - n_stocks * float(data[0])

    # inicialitzem variables
    invested_money=np.zeros(len(data))
    temp_badget=np.zeros(len(data))
    non_strategy=np.zeros(len(data))

    cont=0;
    # iterem les dades de forma sequencial simulant una partida de joc
    for current_value in data:
        # afegim una nova dada i obtenim l'accio recomanada pel broker
        action  = broker.add(float(current_value))
        if action != None:
            if action[1] == -1: # ACCIO COMPRA
                #Gastem el 25% del badget que tenim"
                money2spend=0.25*badget
                new_actions = math.floor(money2spend/float(current_value))
                n_stocks+= new_actions
                badget-=new_actions*float(current_value)
            if action[1] == +1: # ACCIO VENTA
                #Venem el 25% de les accions que tenim"
                actions2sell=round(0.25*n_stocks)
                n_stocks-= actions2sell
                badget+=actions2sell*float(current_value)
        temp_badget[cont]=badget
        invested_money[cont]=n_stocks*float(current_value)
        non_strategy[cont]=(badget/2) + init_stocks*float(current_value)
        cont=cont+1
    return temp_badget,invested_money,non_strategy
method = AdWin(0.95)

for item in data:
    # Creem un objecte broker. Aquest objecte cada cop que entrem una nova dada dira si hem de comprar o vendre accions
    # per_change indica el percentatge de canvi respecte al valor de l'accio per realitzar una compra/venta
    # min_time indica el temps minim que ens hem d'esperar per fer nova accio de compra/venta
    broker= StockMarketWin(method,0.1,10)
    # Executem l'estrtegia de comprar a partir de l'objecte broker i les dades d'entrada. La funcio estrategiaBasica
    # esta definidia dins utilsP4.py. Ella es la responsable de decidir la quantatit de compra o venta d'accios a partir
    # de lasuggeriencia del broker
    temp_badget,invested_money,non_strategy= estrategia(broker,data[item])
    # Mostrem els resultats per pantalla
    print_results(data[item],temp_badget,invested_money,non_strategy)